#include "Julianna.h"
#ifdef in_PC
#endif // in_PC

#include <math.h>
#include <string.h>
#include "Juli_chart.h"
#include "TextBox.h"
/*-------------------for ChartView----------------*/

JUI new_chart(Gem gem, float* pv);
void chartView_onShow(JUI this, ViewEvent e);
int chart_tick_timer(JUI chart_handle);

Li_List charts = NULL; // List<JUI>
JUI chart_handle = NULL;

float sc_x = 0;
float sx = 0, sy = 0;
float zzo = 0;
float sxn = 0, syn = 0;
float zzon = 0;

void chart_file_init()
{
	int n = public_a_cmd_link("chart", cmd_chart);
	if (n >= 0)
		li_cmds[n].annotation = cmd_chart_annotation;
}
int chart_test_demo()
{
	chart_file_init();

	Gem_t gem = { 16, 2, 440, 100 };
	chart_handle = new_chart(&gem, &sx);

	chart_add_ref(chart_handle->id, &sy);
	chart_add_ref(chart_handle->id, &zzo);
	chart_add_ref(chart_handle->id, &sxn);
	chart_add_ref(chart_handle->id, &syn);
	chart_add_ref(chart_handle->id, &zzon);

	public_a_timerArg(chart_tick_timer, Hz(15), chart_handle);
	return 0;
}

// chart about
void chartView_onShow(JUI this, ViewEvent e);
JUI new_chart(Gem gem, float* pv)
{
	ChartView chart = malloc(sizeof(ChartView_t));
	if (!chart)
		return NULL;
	chart->items = new_li(float*);
	if (!chart->items)
	{
		free(chart);
		return NULL;
	}
	if (pv)
		li_add(chart->items, pv);
	chart->lineWidth = gem->width;
	chart->nowAt = 0;
	if (pv)
	{
		chart->axisMin = *pv - 1; // 1e5;// 0x7fffffff;
		chart->axisMax = *pv + 1; //-1e5;// (int)0x80000000;
	}
	else
	{
		chart->axisMin = -1; // 1e5;// 0x7fffffff;
		chart->axisMax = 1;	 //-1e5;// (int)0x80000000;
	}
	chart->yMax = -3.402823466e+38F; //view->axisMin;
	chart->yMin = 3.402823466e+38F;	 // view->yMax;
	chart->scale = chart->axisMax - chart->axisMin;
	chart->status = 0;
	chart->stop = 0;
	pint id = chart;
	JUI bx_ui_handle = new_ui(gem, id, NULL, chartView_onShow);
	if (charts == NULL)
	{
		charts = new_li_cap(JUI, 1);
	}
	li_add(charts, bx_ui_handle);
	return bx_ui_handle;
}
void chart_add_ref(ChartView chart, float* pv)
{
	if (!chart->items)
	{
		chart->items = new_li(float*);
		if (!chart->items)
		{
			return;
		}
	}
	li_add(chart->items, pv);
	chart->status = 1;
}
void chartView_onShow(JUI this, ViewEvent e)
{
#define axisK 0.3f
	const int chart_color_list[] = { Color_red, Color_green, Color_lightblue, Color_yellow, Color_magenta, Color_lgrayblue, Color_brown };
	ChartView view = this->id;
	if (view->stop)
		return;
	if (e == OnCreate)
	{
		view->status = 2;
		Juli_fill_round_rect(-15, 0, this->width + 30, this->height, 15, Color_black);
		//Juli_draw_round_rect(-15, -1, this->width+30, this->height+2,15);
		LCD_changeSize(12);
		only_draw_text(1);
		LCD_set_paint_color(Color_white);

		sprintf(tx, "%.2f", view->axisMax);
		int n = strlen(tx);
		Juli_put_text(this->width - n * 6, 1, tx);

		sprintf(tx, "%.2f", (view->axisMax + view->axisMin) / 2.0f);
		n = strlen(tx);
		Juli_put_text(this->width - n * 6, this->height / 2 - 6, tx);

		sprintf(tx, "%.2f", view->axisMin);
		n = strlen(tx);
		Juli_put_text(this->width - n * 6, this->height - 13, tx);
		LCD_changeSize(24);
		only_draw_text(0);
		LCD_set_paint_color(Color_black);
		return;
	}
	if (view->status)
	{
		Juli_fill(-13, 6, 11, this->height - 12, Color_black);
		int j;
		int y = (this->height - view->items->count * 15 + 4) / 2;
		for (j = 0; j < view->items->count; j++, y += 15)
		{
			Juli_fill(-13, y, 11, 11, chart_color_list[j]);
		}
		if (view->status == 2)
		{
			view->status = 0;
			return;
		}
		view->status = 0;
	}

	if (view->items->count == 0)
		return;
	int eraseAt = (view->nowAt + 5) % this->width; // view->lineWidth;
	Juli_fill(eraseAt, 0, 1, this->height, Color_black);
	int i;
	float** vs = list_content(view->items, float*);

	for (i = 0; i < view->items->count; i++)
	{
		float v = *(vs[i]);

		if (v > view->yMax)
		{
			view->yMax = v;
		}
		if (v < view->yMin)
		{
			view->yMin = v;
		}

		if (v > view->axisMax)
		{
			view->axisMax = v;
			view->scale = v - view->axisMin;
			//v = view->axisMax;
			//view->axisMax = view->axisMin + (v - view->axisMin) / (1.0f - axisK);
			//view->scale = view->axisMax - view->axisMin;
			LCD_changeSize(12);
			//only_draw_text(1);
			LCD_set_paint_color(Color_white);
			LCD_set_background_color(Color_black);
			//Juli_put_text(this->width - 4 * 6, 1, "----");
			sprintf(tx, " %.2f", view->axisMax);
			int n = strlen(tx);
			Juli_put_text(this->width - n * 6, 1, tx);

			sprintf(tx, " %.2f", (view->axisMax + view->axisMin) / 2.0f);
			n = strlen(tx);
			Juli_put_text(this->width - n * 6, this->height / 2 - 6, tx);

			LCD_changeSize(24);
			//only_draw_text(0);
			LCD_set_paint_color(Color_black);
			LCD_set_background_color(Color_white);
		}
		if (v < view->axisMin)
		{
			view->axisMin = v;
			view->scale = view->axisMax - v;
			//v = view->axisMin;
			//view->axisMin = (v - axisK * view->axisMax) / (1.0f - axisK);
			//view->scale = view->axisMax - view->axisMin;

			LCD_changeSize(12);
			//only_draw_text(1);
			LCD_set_paint_color(Color_white);
			LCD_set_background_color(Color_black);
			//Juli_put_text(this->width - 4 * 6, this->height - 13, "----");

			sprintf(tx, " %.2f", (view->axisMax + view->axisMin) / 2.0f);
			int n = strlen(tx);
			Juli_put_text(this->width - n * 6, this->height / 2 - 6, tx);

			sprintf(tx, " %.2f", view->axisMin);
			n = strlen(tx);
			Juli_put_text(this->width - n * 6, this->height - 13, tx);

			LCD_changeSize(24);
			//only_draw_text(0);
			LCD_set_paint_color(Color_black);
			LCD_set_background_color(Color_white);
		}

		//draw point
		int y;
		y = (1.0f - ((v - view->axisMin) / view->scale)) * this->height;
		Juli_draw_point_color(view->nowAt, y, chart_color_list[i]);
	}
	view->nowAt++;
	if (view->nowAt >= /*view->lineWidth*/ this->width)
	{
		view->nowAt = 0;
		//check to small size
		//if ((view->yMax - view->axisMin) / view->scale < (1.0f - axisK))
		//{
		//	view->axisMax = view->axisMin + (view->yMax - view->axisMin) / (1.0f - axisK);
		//	view->scale = view->axisMax - view->axisMin;
		//}
		//if ((view->yMin - view->axisMin) / view->scale > axisK)
		//{
		//	view->axisMin = (view->yMin - axisK * view->axisMax) / (1.0f - axisK);
		//	view->scale = view->axisMax - view->axisMin;
		//}

		view->axisMax = view->yMax + (view->axisMax - view->yMax) * (1.0f - axisK);
		view->axisMin = view->yMin - (view->yMin - view->axisMin) * (1.0f - axisK);
		view->scale = view->axisMax - view->axisMin;

		view->yMax = -3.402823466e+38F; //view->axisMin;
		view->yMin = 3.402823466e+38F;	// view->yMax;

		LCD_changeSize(12);
		only_draw_text(1);
		LCD_set_paint_color(Color_white);

		sprintf(tx, "%.2f", view->axisMax);
		int n = strlen(tx);
		Juli_put_text(this->width - n * 6, 1, tx);

		sprintf(tx, "%.2f", (view->axisMax + view->axisMin) / 2.0f);
		n = strlen(tx);
		Juli_put_text(this->width - n * 6, this->height / 2 - 6, tx);

		sprintf(tx, "%.2f", view->axisMin);
		n = strlen(tx);
		Juli_put_text(this->width - n * 6, this->height - 13, tx);
		LCD_changeSize(24);
		only_draw_text(0);
		LCD_set_paint_color(Color_black);
	}
}



//ChartView chart_view0;
int chart_tick_timer(JUI chart_handle)
{
	sc_x += 0.01f;
	sx = sinf(sc_x);
	sy = cosf(sc_x);
	sxn = -sx;
	syn = -sy;
	zzon = (rand() % 200) / 100.0f;
	;
	juli_show_ui(chart_handle, ByPass);
	return 0;
}

const char* cmd_chart_annotation = "chart control,opt:\n"
" stop [value]\n"
" updateAxis\n"
" to index\n"
" addItem var\n"
" removeItem [all][index]\n"
" newChart [RowColNum][x y w h]\n"
" deleteChart [index]\n"
" fre [newFrequency]";


// chart rm index
int cmd_chart(int n, char* arg[])
{
	if (n < 2)
	{
		if (!chart_handle)
		{
			li_error("no chart assigned", -__LINE__);
		}
		n = charts->count;
		JUI* uis = list_content(charts, JUI);
		int i;
		for (i = 0; i < n; i++)
		{
			ChartView view = cast(uis[i]->id, ChartView);
			sprintf(tx, "%d)%d\n", i, view->items->count);
			lily_out(tx);
		}
		return charts->count;
	}
	char mode = *(arg[1]);
	if (mode == 'n') //chart new
	{
		int x, y, w, h;
		int i;
		Gem_t gem = { 16, 2, 440, 100 };
		if (n == 3)
		{
//			int r = arg[2][0] - '0';
			int c = arg[2][1] - '0';
			n = arg[2][2] - '0';
			w = Screen_width / c;
			h = 100;
			int i;
			x = w * (n % c - 1);
			if (x < 0)
				x = w * (c - 1);
			i = c;
			y = 0;
			while (i < n)
			{
				i += c;
				y++;
			}
			y *= h;
			x += 15;
			w -= 31;
			gem.x = x;
			gem.y = y;
			gem.width = w;
			gem.height = h;
		}
		else if (n == 6)
		{
			for (i = 0; i < 4; i++)
			{
				if (!str_is_numeric(arg[i + 2]))
				{
					li_error("not numeric", -__LINE__);
				}
				int v = atoi(arg[i + 2]);
				((int*)&gem)[i] = v;
			}
		}
		else
		{
			li_error("bad arg", -__LINE__);
		}
		if (gem.y + gem.height > boxView_ui->gem.y)
		{
			int ny = gem.y + gem.height + 2;
			int ddy = ny - boxView_ui->y;
			if (boxView_ui->height - ddy <= 0)
			{
				li_error("no space", -__LINE__);
			}
			boxView_ui->y = ny;
			boxView_ui->height -= ddy;
		}
		chart_handle = new_chart(&gem, NULL);
		juli_show_up();
		public_a_timerArg((TasksArg_def)chart_tick_timer, Hz(15), chart_handle);
		return charts->count;
	}

	if (!chart_handle)
	{
		li_error("now chart assigned", -__LINE__);
	}
	if (mode == 'r') // remove
	{
		assert_msg(n > 2, "bad arg");
		if (*(arg[2]) == 'a') // remove all
		{
			cast(chart_handle->id, ChartView)->items->count = 0;
			cast(chart_handle->id, ChartView)->status = 1;
			return 0;
		}
		if (!isD(arg[2][0]))
		{
			li_error("bad arg", -__LINE__);
		}
		int index = arg[2][0] - '0';
		int ok = list_remove_at(cast(chart_handle->id, ChartView)->items, index);
		if (ok < 0)
		{
			li_error("index er", -__LINE__);
		}
		cast(chart_handle->id, ChartView)->status = 1;
		return cast(chart_handle->id, ChartView)->items->count;
	}

	if (mode == 'a') //add
	{
		assert_msg(n > 2, "bad arg");
		int i;
		for (i = 2; i < n; i++)
		{
			int index = search_var_in_Lily_ui(arg[i]);
			if (index < 0)
			{
				li_error("var not found", -__LINE__);
			}
			int at = ebrace_value_from_string(arg[i]);
			if (at < -1)
			{
				return at;
			}
			if (at == -1)
				at = 0;
			Var var = li_vars + index;
			float* p;
			if (var->type != 'f')
			{
				li_error("type er", -__LINE__);
			}
			if (var->isa)
			{
				p = (var->val.pf) + at;
			}
			else
			{
				if (var->isp)
					p = var->val.pf;
				else
					p = &(var->val.vf);
			}
			chart_add_ref(chart_handle->id, p);
		}
		return cast(chart_handle->id, ChartView)->items->count;
	}

	if (mode == 's') // stop
	{
		ChartView view = cast(chart_handle->id, ChartView);
		if (n == 2)
		{
			view->stop = !view->stop;
		}
		else
		{
			view->stop = arg[2][0] == '1';
		}
		if (view->stop)
		{
			lily_out("stop\n");
			return 1;
		}
		lily_out("resume\n");
		return 0;
	}

	if (mode == 'u')
	{
		ChartView view = cast(chart_handle->id, ChartView);
		view->axisMax = view->yMax;
		view->axisMin = view->yMin;
		view->scale = view->axisMax - view->axisMin;
		return 0;
	}

	if (mode == 'h') // hide
	{
		//ChartView view = cast(chart_handle->id, ChartView);
		int show = 0;

		if (n == 3)
		{
			show = arg[2][0] == '0';
		}

		if (!show) //
		{
			if (chart_handle->hide)
				return 0;
			chart_handle->hide = 1;
			remove_timerArg((TasksArg_def)chart_tick_timer, chart_handle);
			boxView_ui->y -= chart_handle->height;
			boxView_ui->height += chart_handle->height;
			juli_show_up();
			lily_out("hide\n");
			return 1;
		}
		if (!chart_handle->hide)
			return 0;
		chart_handle->hide = 0;
		boxView_ui->y += chart_handle->height;
		;
		boxView_ui->height -= chart_handle->height;
		cast(chart_handle->id, ChartView)->status = 1;
		juli_show_up();
		public_a_timerArg((TasksArg_def)chart_tick_timer, Hz(15), chart_handle);
		lily_out("show\n");
		return 0;
	}

	if (mode == 't') // to index
	{
		assert_msg(n > 2, "bad arg");
		int ind = atoi(arg[2]);
		assert_msg(ind < charts->count, "index error");
		chart_handle = list_content(charts, JUI)[ind];
		return ind;
	}
	if (mode == 'd') //delete [index]
	{
		if (n == 3)
		{
			int ind = atoi(arg[2]);
			assert_msg(ind < charts->count, "index error");
			chart_handle = list_content(charts, JUI)[ind];
		}

		ChartView view = cast(chart_handle->id, ChartView);
		remove_timerArg((TasksArg_def)chart_tick_timer, chart_handle);
		delete_list(view->items);
		free(view);
		list_remove(Julianna, &chart_handle);
		list_remove(charts, &chart_handle);

		if (charts->count)
		{
			chart_handle = list_content(charts, JUI)[charts->count - 1];
			list_reduction(charts);
		}
		else
		{
			chart_handle = NULL;
			delete_list(charts);
			charts = NULL;
		}
		juli_show_up();
		return 0;
	}

	if (mode == 'f') // fre hz
	{
		assert_msg(n > 2, "bad arg");
		//int ind = atoi(arg[2]);
		//assert_msg(ind < charts->count, "index error");
		float fre = 15;
		if (!str_is_numeric(arg[2]))
		{
			li_error("fre error", -__LINE__);
		}
		fre = atof(arg[2]);
		//chart_handle = list_content(charts, JUI*)[ind];
		remove_timerArg((TasksArg_def)chart_tick_timer, chart_handle);
		public_a_timerArg((TasksArg_def)chart_tick_timer, Hz(fre), chart_handle);
		return 0;
	}

	li_error("chart [r,a,s,u,h,t,d,f]", -1045);
}

void collection_fun_math_kit()
{
	public_a_fun_link_n("sin", sinf, 1);
	public_a_fun_link_n("cos", cosf, 1);
	public_a_fun_link_n("tan", tanf, 1);

	public_a_fun_link_n("exp", expf, 1);
	public_a_fun_link_n("ln", logf, 1);
	public_a_fun_link_n("log", log10f, 1);

	public_a_fun_link_n("asin", asinf, 1);
	public_a_fun_link_n("acos", acosf, 1);
	public_a_fun_link_n("atan", atanf, 1);
}
